🎖️GitЯра🎖️
Commit cf014c90311a5f672b0b87f853eadd7d5e2d3449
Parents : 0ec1a0e
Author : James Rich <2199651+jamesarich@users.noreply.github.com>
Signature : Signature validation error
Date : 2026-08-01T09:38:29-05:00
Committer : GitHub <noreply@github.com>
Date : 2026-08-01T14:38:29Z
fix(debug): restore node ID hex annotations broken by the Wire migration (#6532)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Changes
3 files changed, 104 insertions(+), 6 deletions(-)
Diff
diff --git a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/debugging/Debug.kt b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/debugging/Debug.kt
index b4a99d1c74..2cf8f3b3f7 100644
--- a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/debugging/Debug.kt
+++ b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/debugging/Debug.kt
@@ -92,7 +92,9 @@ import org.meshtastic.core.ui.icon.Settings
import org.meshtastic.core.ui.theme.AnnotationColor
import org.meshtastic.feature.settings.debugging.DebugViewModel.UiMeshLog
-private val REGEX_ANNOTATED_NODE_ID = Regex("\\(![0-9a-fA-F]{8}\\)$", RegexOption.MULTILINE)
+// No end-of-line anchor: Wire's toString is single-line, so annotations land mid-line
+// (`from=-1897181963 (!8ee6c775), to=…`), not at line ends as protobuf-java's format did.
+private val REGEX_ANNOTATED_NODE_ID = Regex("\\(![0-9a-fA-F]{8}\\)")
// Suppressions match this screen's pre-existing detekt baseline entries; editing the body reset the baseline hashes.
@Suppress("LongMethod", "ViewModelForwarding", "ModifierMissing")
diff --git a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/debugging/DebugViewModel.kt b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/debugging/DebugViewModel.kt
index 989b3620c8..d1c69b5791 100644
--- a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/debugging/DebugViewModel.kt
+++ b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/debugging/DebugViewModel.kt
@@ -373,9 +373,11 @@ class DebugViewModel(
Packet.getRelayNode(relayNode, nodeList, myNodeNum)?.let { node ->
val relayId = node.user.id
val relayName = node.user.long_name
- val regex = Regex("""\brelay_node: ${relayNode.toUInt()}\b""")
+ // Wire's toString prints `relay_node=245`; rows stored before the Wire
+ // migration carry protobuf-java's `relay_node: 245`. Match both.
+ val regex = Regex("""\brelay_node[=:] ?${relayNode.toUInt()}\b""")
if (regex.containsMatchIn(result)) {
- relayNodeAnnotation = "relay_node: $relayName ($relayId)"
+ relayNodeAnnotation = "relay_node=$relayName ($relayId)"
result = regex.replace(result, placeholder)
}
}
@@ -407,9 +409,13 @@ class DebugViewModel(
/** Look for a single node ID integer in the string and annotate it with the hex equivalent if found. */
private fun StringBuilder.annotateNodeId(nodeId: Int): Boolean {
- val nodeIdStr = nodeId.toUInt().toString()
- // Only match if whitespace before and after
- val regex = Regex("""(?<=\s|^)${Regex.escape(nodeIdStr)}(?=\s|$)""")
+ // Wire's toString prints int fields SIGNED and `=`-delimited (`from=-1897181963,`),
+ // which is what users see since the Wire migration (#6520). Rows stored before it
+ // carry protobuf-java's text format: unsigned, colon-separated, whitespace-bounded
+ // (`from: 2397785333`). Match either representation at a value position.
+ val signed = Regex.escape(nodeId.toString())
+ val unsigned = Regex.escape(nodeId.toUInt().toString())
+ val regex = Regex("""(?<=[=\s]|^)($signed|$unsigned)(?=[,}\s]|$)""")
if (!regex.containsMatchIn(this)) return false
regex.findAll(this).toList().asReversed().forEach {
val idx = it.range.last + 1
diff --git a/feature/settings/src/commonTest/kotlin/org/meshtastic/feature/settings/debugging/DebugViewModelTest.kt b/feature/settings/src/commonTest/kotlin/org/meshtastic/feature/settings/debugging/DebugViewModelTest.kt
index 6e61dc94d9..8eb9aaec3d 100644
--- a/feature/settings/src/commonTest/kotlin/org/meshtastic/feature/settings/debugging/DebugViewModelTest.kt
+++ b/feature/settings/src/commonTest/kotlin/org/meshtastic/feature/settings/debugging/DebugViewModelTest.kt
@@ -21,6 +21,7 @@ import dev.mokkery.matcher.any
import dev.mokkery.mock
import dev.mokkery.verify
import io.kotest.matchers.shouldBe
+import io.kotest.matchers.string.shouldContain
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.UnconfinedTestDispatcher
@@ -197,4 +198,93 @@ class DebugViewModelTest {
viewModel.requestDeleteAllLogs()
verify { alertManager.showAlert(titleRes = any(), messageRes = any(), onConfirm = any()) }
}
+
+ // Regression tests for #6520: Wire's toString prints int fields SIGNED and `=`-delimited
+ // (`from=-559038737,`), which the annotation regexes — written for protobuf-java's
+ // unsigned, whitespace-bounded text format — silently stopped matching. These go through
+ // the real generated toString, so they hold whichever wire format is in use.
+
+ @Test
+ fun `packet log annotates signed Wire-format from and to with hex`() = runTest {
+ val packet = org.meshtastic.core.testing.TestDataFactory.createTestPacket(from = 0xDEADBEEF.toInt(), to = -1)
+ meshLogRepository.insert(
+ org.meshtastic.core.model.MeshLog(
+ uuid = "1",
+ message_type = "Packet",
+ received_date = 1L,
+ raw_message = "",
+ fromRadio = org.meshtastic.proto.FromRadio(packet = packet),
+ ),
+ )
+
+ val logs = viewModel.loadLogsForExport()
+
+ logs.size shouldBe 1
+ logs[0].logMessage shouldContain "(!deadbeef)"
+ logs[0].logMessage shouldContain "(!ffffffff)"
+ }
+
+ @Test
+ fun `packet log annotates relay_node with the known node's name`() = runTest {
+ nodeRepository.setNodes(
+ listOf(
+ org.meshtastic.core.testing.TestDataFactory.createTestNode(
+ num = 0x000001AA,
+ userId = "!000001aa",
+ longName = "Relay Node",
+ lastHeard = 100,
+ ),
+ ),
+ )
+ val packet = org.meshtastic.core.testing.TestDataFactory.createTestPacket(from = 5, to = -1, relayNode = 0xAA)
+ meshLogRepository.insert(
+ org.meshtastic.core.model.MeshLog(
+ uuid = "1",
+ message_type = "Packet",
+ received_date = 1L,
+ raw_message = "",
+ fromRadio = org.meshtastic.proto.FromRadio(packet = packet),
+ ),
+ )
+
+ val logs = viewModel.loadLogsForExport()
+
+ logs[0].logMessage shouldContain "relay_node=Relay Node (!000001aa)"
+ }
+
+ @Test
+ fun `packet log annotates unknown relay_node with hex`() = runTest {
+ val packet = org.meshtastic.core.testing.TestDataFactory.createTestPacket(from = 5, to = -1, relayNode = 0xF5)
+ meshLogRepository.insert(
+ org.meshtastic.core.model.MeshLog(
+ uuid = "1",
+ message_type = "Packet",
+ received_date = 1L,
+ raw_message = "",
+ fromRadio = org.meshtastic.proto.FromRadio(packet = packet),
+ ),
+ )
+
+ val logs = viewModel.loadLogsForExport()
+
+ logs[0].logMessage shouldContain "(!000000f5)"
+ }
+
+ @Test
+ fun `node info log still annotates legacy protobuf-java text format`() = runTest {
+ meshLogRepository.insert(
+ org.meshtastic.core.model.MeshLog(
+ uuid = "1",
+ message_type = "NodeInfo",
+ received_date = 1L,
+ raw_message = "node_info {\n num: 3735928559\n}",
+ fromRadio =
+ org.meshtastic.proto.FromRadio(node_info = org.meshtastic.proto.NodeInfo(num = 0xDEADBEEF.toInt())),
+ ),
+ )
+
+ val logs = viewModel.loadLogsForExport()
+
+ logs[0].logMessage shouldContain "num: 3735928559 (!deadbeef)"
+ }
}
Served by rngit 1.5.2 - Generated in 0.11s